package com.gitee.wsl.doc.prosemirror.model.dom.parser.rule

import com.fleeksoft.ksoup.nodes.Element
import com.fleeksoft.ksoup.nodes.Node as DOMNode
import com.gitee.wsl.doc.prosemirror.model.attr.Attrs
import com.gitee.wsl.doc.prosemirror.model.fragment.Fragment
import com.gitee.wsl.doc.prosemirror.model.Schema
import com.gitee.wsl.doc.prosemirror.model.dom.ContentElement
import com.gitee.wsl.doc.prosemirror.model.dom.PreserveWhitespace
import com.gitee.wsl.doc.prosemirror.model.dom.parser.ParseRuleMatch

// Parse rule targeting a DOM element.
interface TagParseRule : ParseRule {
    // A CSS selector describing the kind of DOM elements to match.
    val tag: String

    // The namespace to match. Nodes are only matched when the
    // namespace matches or this property is null.
    val namespace: String?

    // The name of the node type to create when this rule matches. Each
    // rule should have either a `node`, `mark`, or `ignore` property
    // (except when it appears in a [node](#model.NodeSpec.parseDOM) or
    // [mark spec](#model.MarkSpec.parseDOM), in which case the `node`
    // or `mark` property will be derived from its position).
    var node: String?

    // A function used to compute the attributes for the node or mark
    // created by this rule. Can also be used to describe further
    // conditions the DOM element or style must match. When it returns
    // `false`, the rule won't match. When it returns null or undefined,
    // that is interpreted as an empty/default set of attributes.
    val getNodeAttrs: ((node: Element) -> ParseRuleMatch)?

    // For rules that produce non-leaf nodes, by default the content of
    // the DOM element is parsed as content of the node. If the child
    // nodes are in a descendent node, this may be a CSS selector
    // string that the parser must use to find the actual content
    // element, or a function that returns the actual content element
    // to the parser.
    val contentElement: ContentElement?

    // Can be used to override the content of a matched node. When
    // present, instead of parsing the node's child nodes, the result of
    // this function is used.
    val getContent: ((node: DOMNode, schema: Schema) -> Fragment?)?

    // Controls whether whitespace should be preserved when parsing the
    // content inside the matched element. `false` means whitespace may
    // be collapsed, `true` means that whitespace should be preserved
    // but newlines normalized to spaces, and `"full"` means that
    // newlines should also be preserved.
    val preserveWhitespace: PreserveWhitespace?
}


data class TagParseRuleImpl(
    override val tag: String,
    override val namespace: String? = null,
    override val priority: Int? = null,
    override val consuming: Boolean? = null,
    override val context: String? = null,
    override var node: String? = null,
    override var mark: String? = null,
    override val ignore: Boolean? = null,
    override val closeParent: Boolean? = null,
    override val skip: Boolean? = null,
    override var attrs: Attrs? = null,
    override val getNodeAttrs: ((node: Element) -> ParseRuleMatch)? = null,
    override val contentElement: ContentElement? = null,
    override val getContent: ((node: DOMNode, schema: Schema) -> Fragment?)? = null,
    override val preserveWhitespace: PreserveWhitespace? = null
) : TagParseRule, ParseRule {
    override fun copyRule() = this.copy()
}

fun isTagRule(rule: ParseRule) = (rule as? TagParseRule)?.tag != null